#include <stdlib.h>
#include <algorithm>
#include "rational.h"

int Rational::gcd(int a, int b) {
    if (a == b) {
        return a;    
    } else if (b < a) { 
        return gcd(b, a);        
    } else {
        return gcd(a, b - a);        
    }
}

void Rational::simplify() {
    int divisor = gcd(abs(numerator), denominator);
    numerator /= divisor;
    denominator /= divisor;
}

void Rational::normalize() {
    if (denominator < 0) {
        denominator = -denominator;
        numerator = -numerator;   
    }
}

Rational::Rational(int numerator, int denominator):
    numerator(numerator),
    denominator(denominator) {
    normalize();
    simplify();
}

Rational & Rational::operator +=(const Rational & rhs) {
    numerator = numerator * rhs.denominator + rhs.numerator * denominator;
    denominator = denominator * rhs.denominator;
    simplify();    
    return *this;
}

Rational & Rational::operator -=(const Rational & rhs) {
    *this += -rhs;
    return *this;
}


Rational & Rational::operator *=(const Rational & rhs) {
    numerator *= rhs.numerator;
    denominator *= rhs.denominator;
    simplify();
    return *this;
}  

Rational & Rational::operator /=(const Rational & rhs) {
    return *this *= rhs.inv();
}

Rational Rational::inv() const {
    Rational result(*this);
    std::swap(result.numerator, result.denominator);
    result.normalize();
    return result;
}

Rational Rational::operator -() const {
    Rational result(-numerator, denominator);
    return result;
}

Rational & Rational::operator ++() {
	return *this += 1;
}

Rational Rational::operator ++(int) {
	Rational result = *this;
	++(*this);
	return result;
}

Rational & Rational::operator --() {
	return *this -= 1;
}

Rational Rational::operator --(int) {
	Rational result = *this;
	--(*this);
	return result;
}

bool operator ==(const Rational & lhs, const Rational & rhs) {
    return lhs.numerator == rhs.numerator && lhs.denominator == rhs.denominator;
}
bool operator <=(const Rational & lhs, const Rational & rhs) {
    return !(lhs > rhs);
}
bool operator >=(const Rational & lhs, const Rational & rhs) {
    return !(lhs < rhs);
}
bool operator <(const Rational & lhs, const Rational & rhs) {
    return lhs.numerator * rhs.denominator < rhs.numerator * lhs.denominator;
}
bool operator >(const Rational & lhs, const Rational & rhs) {
    return rhs < lhs;
}

Rational::operator double() const {
    return numerator / (double) denominator;
}

Rational operator +(const Rational & lhs, const Rational & rhs) { 
    Rational result(lhs);
    return result += rhs;
}

Rational operator -(const Rational & lhs, const Rational & rhs) {
    Rational result(lhs);
    return result -= rhs;
}

Rational operator *(const Rational & lhs, const Rational & rhs) {
    Rational result(lhs);
    return result *= rhs;
}

Rational operator /(const Rational & lhs, const Rational & rhs) {
    Rational result(lhs);
    return result /= rhs;
}
